package com.sh.data.engine.domain.normalization.standard.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.sh.data.engine.common.exception.InvalidParamException;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.base.model.PageResult;
import com.sh.data.engine.domain.common.service.CommonService;
import com.sh.data.engine.domain.normalization.standard.model.domain.*;
import com.sh.data.engine.domain.normalization.standard.model.enums.BoundStatusEnum;
import com.sh.data.engine.domain.normalization.standard.model.mapper.DictionaryMappingReportDomainMapper;
import com.sh.data.engine.domain.normalization.standard.model.mapper.DictionaryMappingReportEntityMapper;
import com.sh.data.engine.domain.normalization.standard.model.mapper.MappingReportDomainMapper;
import com.sh.data.engine.domain.normalization.standard.model.param.DictionaryMappingReportParam;
import com.sh.data.engine.domain.normalization.standard.model.param.MappingReportDetailParam;
import com.sh.data.engine.domain.normalization.standard.model.param.MappingReportParam;
import com.sh.data.engine.domain.normalization.standard.service.IDictionaryMappingDetailService;
import com.sh.data.engine.domain.normalization.standard.service.IDictionaryMappingReportService;
import com.sh.data.engine.domain.normalization.standard.service.IDictionaryService;
import com.sh.data.engine.domain.shims.db.BaseDbManager;
import com.sh.data.engine.domain.shims.db.model.TableInfoDomain;
import com.sh.data.engine.repository.dao.normalization.standard.DictionaryMappingReportMapper;
import com.sh.data.engine.repository.dao.normalization.standard.entity.DictionaryEntity;
import com.sh.data.engine.repository.dao.normalization.standard.entity.DictionaryMappingReportEntity;
import com.sh.data.engine.repository.dao.workspace.manager.entity.StorageEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author jingchen.hr
 */
@Service
@Slf4j
public class DictionaryMappingReportServiceImpl
    extends ServiceImpl<DictionaryMappingReportMapper, DictionaryMappingReportEntity>
    implements IDictionaryMappingReportService {

    @Autowired
    private DictionaryMappingReportMapper dictionaryMappingReportMapper;

    @Autowired
    private IDictionaryMappingDetailService dictionaryMappingDetailService;

    @Autowired
    private IDictionaryService dictionaryService;

    //    @Autowired
//    private ProjectService projectService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private MappingReportDomainMapper mappingReportDomainMapper;

    @Autowired
    private DictionaryMappingReportEntityMapper dictionaryMappingReportEntityMapper;

    @Autowired
    private DictionaryMappingReportDomainMapper dictionaryMappingReportDomainMapper;

    private static final Integer DAYS_OF_TEND = 6;

    @Override
    public List<DictionaryMappingReportDetailDomain> reportDetail(MappingReportParam param) {
        DictionaryMappingReportEntity reportEntity =
            dictionaryMappingReportMapper.selectById(param.getId());
        if (reportEntity == null) {
            throw new InvalidParamException("当前记录已不存在");
        }

        if (StringUtils.isBlank(reportEntity.getTableFieldJson())) {
            return Collections.emptyList();
        }
        List<FieldDomain> fieldDomains =
            JSON.parseArray(reportEntity.getTableFieldJson(), FieldDomain.class);

        if (CollectionUtils.isEmpty(fieldDomains)) {
            return Collections.emptyList();
        }

        //    List<DictionaryMappingDetailDomain> detailList =
        //        dictionaryMappingDetailService.getListByTblId(reportEntity.getTblId());
        //    Map<String, DictionaryMappingDetailDomain> fieldNameMap =
        //        detailList.stream()
        //            .collect(
        //                Collectors.toMap(
        //                    DictionaryMappingDetailDomain::getFieldName,
        //                    Function.identity(),
        //                    (k1, k2) -> k1));
        //    List<Long> dictIds =
        //        detailList.stream()
        //            .map(DictionaryMappingDetailDomain::getDictId)
        //            .distinct()
        //            .collect(Collectors.toList());
        //            Map<Long, DictionaryEntity> dictionaryEntityMap =
        // dictionaryService.getMapByIds(dictIds);

        // 获取所有已发布标准
        var projectId = ServletUtils.getProjectId();
        List<DictionaryDomain> allDictionary =
            dictionaryService.getRealeseDic(projectId);
        // 标准名-标准实体 映射
        Map<String, DictionaryDomain> map =
            allDictionary.stream()
                .collect(
                    Collectors.toMap(
                        DictionaryDomain::getDictNameEn, Function.identity(), (k1, k2) -> k1));

        List<String> alldics =
            allDictionary.stream().map(DictionaryDomain::getDictNameEn).collect(Collectors.toList());

        List<DictionaryMappingReportDetailDomain> resultList = new LinkedList<>();
        fieldDomains.forEach(
            fieldInfoDomain -> {
                DictionaryMappingReportDetailDomain domain = new DictionaryMappingReportDetailDomain();
                domain.setFieldName(fieldInfoDomain.getFieldName());
                domain.setFieldDes(fieldInfoDomain.getComment());

                // DictionaryMappingDetailDomain detail =
                // fieldNameMap.get(fieldInfoDomain.getFieldName());
                DictionaryDomain detail = map.get(fieldInfoDomain.getFieldName());
                if (detail != null) {
                    // domain.setFieldDes(detail.getFieldDes());
                    //            DictionaryEntity dictionaryEntity =
                    // dictionaryEntityMap.get(detail.getDictId());
                    //            if (dictionaryEntity != null) {
                    //              domain.setDictId(dictionaryEntity.getId());
                    //              domain.setDictNameCn(dictionaryEntity.getDictNameCn());
                    //              domain.setDictNameEn(dictionaryEntity.getDictNameEn());
                    //            }
                    domain.setDictId(detail.getId());
                    domain.setDictNameCn(detail.getDictNameCn());
                    domain.setDictNameEn(detail.getDictNameEn());
                }
                resultList.add(domain);
            });
        return resultList;
    }

    @Override
    public Date getMaxUpdateTime(Long projectId) {
        Page<DictionaryMappingReportEntity> page = new Page<>(1, 1);
        // projectId, updateTime索引
        LambdaQueryWrapper<DictionaryMappingReportEntity> query =
            new LambdaQueryWrapper<DictionaryMappingReportEntity>()
                .eq(DictionaryMappingReportEntity::getRowState, 1)
                .eq(DictionaryMappingReportEntity::getProjectId, projectId)
                .orderByDesc(DictionaryMappingReportEntity::getUpdateTime);

        Page<DictionaryMappingReportEntity> dictionaryMappingReportEntityPage =
            dictionaryMappingReportMapper.selectPage(page, query);
        return CollectionUtils.isNotEmpty(dictionaryMappingReportEntityPage.getRecords())
            ? Optional.ofNullable(dictionaryMappingReportEntityPage.getRecords().get(0))
            .map(DictionaryMappingReportEntity::getUpdateTime)
            .orElse(null)
            : null;
    }

    @Override
    public List<TableStandardDomain> tableStandardList(String tableName) {
        var projectId = ServletUtils.getProjectId();
//        ProjectEntity project = projectService.getProjectById(projectId);
        BaseDbManager dbManager = commonService.getStorageDbManagerByProjctId(projectId);
        StorageEntity storage = commonService.getStorage(projectId);

        TableInfoDomain tableInfoDomain = null;
        try {
            tableInfoDomain =
                dbManager.getTableInfoByTableName(storage.getRmdbs().getDbName(), tableName);
        } catch (SQLException throwables) {

        }
        // TableInfoDomain tableInfoDomain = hiveService.getTableByName(project.getName(), tableName);
        if (tableInfoDomain == null) {
            throw new InvalidParamException("表不存在");
        }

        List<DictionaryMappingDetailDomain> detailList =
            dictionaryMappingDetailService.getListByTblId(tableInfoDomain.getTblId());
        List<Long> dictIds =
            detailList.stream()
                .map(DictionaryMappingDetailDomain::getDictId)
                .distinct()
                .collect(Collectors.toList());
        Map<Long, DictionaryEntity> dictMap = dictionaryService.getMapByIds(dictIds);

        List<TableStandardDomain> resultList = new ArrayList<>();
        detailList.forEach(
            detail -> {
                if (Objects.equals(detail.getBoundStatus(), BoundStatusEnum.BOUND.getVal())) {
                    TableStandardDomain domain = new TableStandardDomain();
                    domain.setFieldName(detail.getFieldName());
                    DictionaryEntity dictionaryEntity = dictMap.get(detail.getDictId());
                    if (dictionaryEntity != null) {
                        domain.setId(dictionaryEntity.getId());
                        domain.setDictNameEn(dictionaryEntity.getDictNameEn());
                        domain.setDictNameCn(dictionaryEntity.getDictNameCn());
                    }
                    resultList.add(domain);
                }
            });
        return resultList;
    }

    @Override
    public PageResult<MappingReportDomain> listReport(
        MappingReportDetailParam param, Integer exportFlag) {
        var projectId = ServletUtils.getProjectId();
        List<DictionaryMappingReportEntity> reportList = Lists.newArrayList();
        Long total = 0L;
        Long pageTotal = 0L;
        // 导出
        if (exportFlag == 1) {
            reportList =
                dictionaryMappingReportMapper.getAllReportList(projectId, param.getDatasourceBaseId());
        } else {
            //      result =
            //          dictionaryMappingReportMapper.queryList(
            //              projectId, param.getDatasourceBaseId(), param.getPageNum(),
            // param.getPageSize());
            LambdaQueryWrapper<DictionaryMappingReportEntity> query =
                new QueryWrapper<DictionaryMappingReportEntity>().lambda();
            query
                .eq(Objects.nonNull(projectId), DictionaryMappingReportEntity::getProjectId, projectId)
                .eq(DictionaryMappingReportEntity::getDatasourceBaseId, param.getDatasourceBaseId());
            Page<DictionaryMappingReportEntity> page =
                this.page(new Page<>(param.getPageNum(), param.getPageSize()), query);
            total = page.getTotal();
            pageTotal = page.getPages();
            reportList = page.getRecords();
        }

        List<MappingReportDomain> responseList = new ArrayList<>();
        reportList.forEach(
            reportEntity -> {
                MappingReportDomain response = mappingReportDomainMapper.map(reportEntity);
                response.setTblName(reportEntity.getTableName());
                response.setTblDes(reportEntity.getTableDes());
                if (Objects.equals(0, reportEntity.getMapSource())) {

                    TableInfoDomain tableInfoDomain = null;
                    try {

                    } catch (Exception throwables) {

                    }
                    if (tableInfoDomain != null) {
                        response.setTblName(tableInfoDomain.getTableName());
                        response.setTblDes(tableInfoDomain.getTableComment());
                    }
                }
                response.initHitStr();
                response.initPercentStr();
                responseList.add(response);
            });
        PageResult<MappingReportDomain> pageResult = new PageResult<>();
        pageResult.setResult(responseList);
        pageResult.setTotalElements(total);
        pageResult.setPageSize(param.getPageSize());
        pageResult.setPageNum(param.getPageNum());
        pageResult.setTotalPages(Integer.valueOf(pageTotal.toString()));
        return pageResult;
    }

    @Override
    public List<DictionaryTrendDomain> tableTrend(Long datasourceBaseId) {

        var projectId = ServletUtils.getProjectId();

        List<DictionaryTrendDomain> domains = Lists.newArrayList();

        List<DictionaryMappingReportEntity> allReportList =
            dictionaryMappingReportMapper.getAllReportList(projectId, datasourceBaseId);

        for (DictionaryMappingReportEntity trendEntity : allReportList) {
            String date = DateFormatUtils.format(trendEntity.getUpdateTime(), "yyyy-MM-dd");

            domains.add(
                DictionaryTrendDomain.builder().date(date).count(trendEntity.getHitCount()).build());
        }
        return domains;
    }

    public int updateHitCountWhenDeleteDictionary(Long dicMappingId) {
        if (null == dicMappingId) {
            return 0;
        }
        List<DictionaryMappingDetailDomain> byDicMappingId =
            dictionaryMappingDetailService.getByDicMappingId(dicMappingId);
        List<Long> tblIds = byDicMappingId.stream().map(i -> i.getTblId()).collect(Collectors.toList());
        Long projectId = byDicMappingId.get(0).getProjectId();
        LambdaQueryWrapper<DictionaryMappingReportEntity> query =
            new QueryWrapper<DictionaryMappingReportEntity>().lambda();
        query.eq(DictionaryMappingReportEntity::getProjectId, projectId);
        List<DictionaryMappingReportEntity> sqlResult = dictionaryMappingReportMapper.selectList(query);
        List<DictionaryMappingReportEntity> result =
            sqlResult.stream().filter(i -> tblIds.contains(i.getTblId())).collect(Collectors.toList());
        result.forEach(
            i -> {
                Integer hitCount = i.getHitCount();
                if (hitCount > 0) {
                    i.setHitCount(hitCount - 1);
                    i.setUpdateTime(new Date());
                    dictionaryMappingReportMapper.updateById(i);
                }
            });
        return result.size();
    }

    public int deleteByTblIdList(List<Long> tblIds) {
        return dictionaryMappingReportMapper.deleteByTblIdList(tblIds);
    }

    public int updateFieldById(
        Long id, Integer fieldCount, String fieldJson, String tableName, String tableComment) {
        if (null == id) {
            return 0;
        }
        DictionaryMappingReportEntity report = new DictionaryMappingReportEntity();

        report.setId(id);
        report.setFieldCount(fieldCount);
        report.setTableFieldJson(fieldJson);
        report.setTableName(tableName);
        report.setTableDes(tableComment);
        report.setUpdateTime(new Date());

        return dictionaryMappingReportMapper.updateById(report);
    }

    public int updateHitCountById(Long id, Integer hitCount) {
        if (null == id) {
            return 0;
        }
        DictionaryMappingReportEntity report = new DictionaryMappingReportEntity();
        report.setId(id);
        report.setHitCount(hitCount);
        report.setUpdateTime(new Date());
        return dictionaryMappingReportMapper.updateById(report);
    }

    public DictionaryMappingReportDomain saveReport(DictionaryMappingReportParam param) {
        if (null != param) {
            DictionaryMappingReportEntity reportEntity = dictionaryMappingReportEntityMapper.map(param);
            reportEntity.setCreateTime(new Date());
            reportEntity.setUpdateTime(new Date());
            dictionaryMappingReportMapper.insert(reportEntity);
            return dictionaryMappingReportDomainMapper.map(reportEntity);
        }
        return null;
    }

    public DictionaryMappingReportDomain saveReportForHiveTable(DictionaryMappingReportParam param) {
        DictionaryMappingReportParam report =
            DictionaryMappingReportParam.builder()
                .projectId(param.getProjectId())
                .tblId(param.getTblId())
                .hitCount(0)
                .fieldCount(param.getFieldCount())
                .tableFieldJson(param.getTableFieldJson())
                .tableDes(param.getTableDes())
                .mapSource(0)
                .datasourceBaseId(param.getDatasourceBaseId())
                .rowState(1)
                .tableName(param.getTableName())
                .tableDes(param.getTableDes())
                .createTime(new Date())
                .updateTime(new Date())
                .jdbcUrl(param.getJdbcUrl())
                .dbName(param.getDbName())
                .build();
        return this.saveReport(report);
    }

    public DictionaryMappingReportDomain getReportByProjectIdAndTblId(Long projectId, Long tblId) {
        DictionaryMappingReportEntity reportEntity =
            dictionaryMappingReportMapper.getReportByProjectIdAndTblId(projectId, tblId);
        return dictionaryMappingReportDomainMapper.map(reportEntity);
    }

    public DictionaryMappingReportDomain getReportByProjectIdAndTblInfo(
        Long projectId, String jdbcUrl, String dbName, String tblName) {
        DictionaryMappingReportEntity reportEntity =
            dictionaryMappingReportMapper.getReportByProjectIdAndTblInfo(
                projectId, jdbcUrl, dbName, tblName);
        return dictionaryMappingReportDomainMapper.map(reportEntity);
    }

    public int deleteReportByMapsource(Long projectId, Integer mapsource) {
        LambdaQueryWrapper<DictionaryMappingReportEntity> query =
            new QueryWrapper<DictionaryMappingReportEntity>().lambda();
        query
            .eq(DictionaryMappingReportEntity::getProjectId, projectId)
            .eq(DictionaryMappingReportEntity::getMapSource, mapsource);
        return dictionaryMappingReportMapper.delete(query);
    }

    public int saveDictMappingReportList(List<DictionaryMappingReportParam> params) {
        if (CollectionUtils.isEmpty(params)) {
            return 0;
        }
        List<DictionaryMappingReportEntity> reports = dictionaryMappingReportEntityMapper.map(params);
        reports.forEach(
            report -> {
                report.setCreateTime(new Date());
                report.setUpdateTime(new Date());
            });
        this.saveBatch(reports);
        return reports.size();
    }

    public List<Long> getTblIdsByProjectId(Long projectId) {
        return dictionaryMappingReportMapper.getTblIdsByProjectId(projectId);
    }
}
